package com.tutk.p2p;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import cn.innosmart.aq.application.AQApplication;
import cn.innosmart.aq.manager.LoginManager;
import cn.innosmart.aq.util.AppUtil;
import cn.innosmart.aq.util.LanSearchUtil;
import cn.innosmart.aq.util.MD5Util;
import cn.innosmart.aq.util.SystemConstant;
import cn.innosmart.aq.util.ZipUtil;


public class ConnectionEntity {

    // APP 订阅topic 默认值"app_client", 在MQTT连接时需要改为唯一的 client id
    public static String TOPIC_APP_CLIENT = "app_client";
    //连接方法名称
    public final String DEVICELIST = "DEVICELIST";
    public final String RULELIST = "RULELIST";
    public final String PLACELIST = "PLACELIST";
    public final String PLACEADD = "PLACEADD";
    public final String PLACEREMOVE = "PLACEREMOVE";
    public final String DEVICEINCLUDE = "DEVICEINCLUDE";
    public final String DEVICEEXCLUDE = "DEVICEEXCLUDE";
    public final String ABORTMODE = "ABORTMODE";
    public final String DEVICEUPDATE = "DEVICEUPDATE";
    public final String DEVICECONTROL = "DEVICECONTROL";
    public final String REMOVEFAILEDNODE = "REMOVEFAILEDNODE";
    public final String SYSTEMMANAGER_GETDATA = "SYSTEMMANAGER_GETDATA";
    public final String SYSTEMMANAGER_SETDATA = "SYSTEMMANAGER_SETDATA";

    private final String TAG = "ConnectEntity";
    private final int UNKNOWN = 0;
    private final int LAN = 1;
    private final int WLAN = 2;
    public String EVENT_TOPIC_DEVICE_UPDATED = "UPLINK/%s/event/DeviceManager.deviceUpdated";
    public String EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE = "UPLINK/%s/event/SystemManager.FirmwareDownloadPercentage";
    public String EVENT_TOPIC_UPGRADE_MD5 = "UPLINK/%s/event/SystemManager.FirmwareMD5";
    public String EVENT_TOPIC_UPGRADE_UPGRADING = "UPLINK/%s/event/SystemManager.FirmwareUpgrading";
    public String EVENT_TOPIC_UPGRADE_REBOOT = "UPLINK/%s/event/SystemManager.Reboot";
    /**
     * Flags属性，用来判断是否成功
     */
    public boolean isChecked = false;
    public IConnectionEntity iConnectionEntity;
    public ArrayList<String> flags;
    public boolean isConnect = false;
    public HashMap<Long, ResponseHandler> mReqRspHashMap = new HashMap<Long, ResponseHandler>();
    public int CONTYPE = 0;
    public boolean isExist;
    public ArrayList<String> countdowns = new ArrayList<>();
    // APP 端订阅的所有 Event 事件 topic
    private String VERIFYPUBLISHLINK = "DOWNLINK/%s/device_core";
    private String VERIFYSUBSCRIBELINK = "UPLINK/%1$s/%2$s";
    private String DOWNLINK = "DOWNLINK/%s/device_core";
    private String UPLINK = "UPLINK/%1$s/%2$s";
    private String EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED = "UPLINK/%s/event/channel.sensorvalueUpdated";
    private String EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED = "UPLINK/%s/event/channel.basicvalueUpdated";
    private String EVENT_TOPIC_GATEWAY_MODECHANGED = "UPLINK/%s/event/gateway.modeChanged";
    private String EVENT_TOPIC_PLACE_MAINTAINCHANGED = "UPLINK/%s/event/PlaceManager.MaintainChanged";
    private String EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED = "UPLINK/%s/event/gateway.deviceExcluded";
    private String EVENT_TOPIC_GATEWAY_DEVICEINCLUDED = "UPLINK/%s/event/gateway.deviceIncluded";
    private String uid;
    private String password;
    private String userName;
    //-1未知  0失败  1成功
    private int connectStatus = -1;
    private String encode_key;
    private String connectHost = null;
    private Context context;
    private BroadcastReceiver connectionReceiver;
    private ConnectivityManager mConnectivityManager;
    private NetworkInfo netInfo;
    private EventsCallback mEventsCallback = null;
    private String[] topics = null;
    private MqttClient mqttClient;
    private String mMQTTClientID;
    private MqttConnectOptions mMqttOptions;
    private String mqttUserName = "admin";
    private String mqttPassWord = "password";
    private String Tag = "ConnectionEntity";
    private ScheduledExecutorService mqttScheduler;
    private String WlanHost = "tcp://mqtt.innosmart.cn:1883";
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    break;
                case 1:
                    sendLogin();
                    break;
                case 2:
                    break;
            }
        }
    };

    /**
     * @param context           上下文
     * @param uid               连接的Uid
     * @param userName          手机号
     * @param password          密码
     * @param iConnectionEntity
     */
    public ConnectionEntity(Context context, String uid, String userName, String password, IConnectionEntity iConnectionEntity) {
        this.context = context;
        this.uid = uid;
        this.password = password;
        this.userName = userName;
        this.iConnectionEntity = iConnectionEntity;
        //连接的ClientID
        mMQTTClientID = AQApplication.getInstance().getMqttClientId();
        flags = new ArrayList<String>();
    }

    public void ableCheck() {
        isChecked = true;
    }

    public void disableCheck() {
        isChecked = false;
    }

    /**
     * 初始化连接
     *
     * @param TYPE 连接类型 LAN 1   WLAN 2
     * @param host 主机
     */
    public void init(int TYPE, String host) {
        this.connectHost = host;
        CONTYPE = TYPE;
        //格式化Topic
        formatTopic(TYPE, uid);
        //连接
        connect();
    }

    /**
     * 注册网络监听器
     */
    private void register() {
        connectionReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(final Context context, Intent intent) {
                String action = intent.getAction();
                if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                    mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                    netInfo = mConnectivityManager.getActiveNetworkInfo();
                    if (netInfo != null && netInfo.isAvailable()) {
                        /////////////网络连接
                        String name = netInfo.getTypeName();
                        if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                            /////WiFi网络
                            System.out.println("切成wifi");
                            if (isConnect) {
                                ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1007);
                                isConnect = false;
                                resetConnect();
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            Thread.sleep(5000);
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                        lanSearch(context, uid);
                                    }
                                }).start();

                            }
                        } else if (netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
                            /////有线网络
                            System.out.println("切成有限网络");
                        } else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                            /////////3g网络
                            System.out.println("切成3G网络");
                            if (isConnect) {
                                isConnect = false;
                                ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1007);
                                resetConnect();
                                init(WLAN, WlanHost);
                            }
                        }
                    } else {
                        ////////网络断开
                        System.out.println("网络断开");
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1006);
                    }
                }
            }
        };
        IntentFilter mFilter = new IntentFilter();
        mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(connectionReceiver, mFilter);
    }

    /**
     * 取消网络状态监听
     */
    private void unRegister() {
        if (connectionReceiver != null) {
            context.unregisterReceiver(connectionReceiver);
            connectionReceiver = null;
            System.out.println("取消注册");
        } else {
            System.out.println("没有取消注册");
        }
    }

    /**
     * 发送连接参数
     */
    private void sendConnect() { //仅仅用于局域网
        try {
            JSONObject jsParams = new JSONObject();
            jsParams.put("clientid", mMQTTClientID);
            LoginManager.getInstance().Connect(this, jsParams.toString(), new LoginManager.ConnectCallBack() {
                @Override
                public void onResponseCallBack(int ret, String str) {
                    if (ret == 0) {
                        encode_key = str;
                        mHandler.sendEmptyMessage(1);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送登录消息
     */
    private void sendLogin() {
        try {
            JSONObject jsParams = new JSONObject();
            JSONObject data = new JSONObject();
            data.put("username", userName);
            data.put("password", password);
            data.put("clientid", mMQTTClientID);
            jsParams.put("data", data);
            LoginManager.getInstance().Login(this, jsParams.toString(), new LoginManager.LoginCallBack() {
                @Override
                public void onResponseCallBack(int ret, String str) {
                    if (ret == 0) {
                        connectStatus = 1;
                        System.out.println("Login OK");
                        ping();
                        //连接成功
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1004);
                        register();
                    } else if (ret == -1) {
                        //手机号密码错误
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1005);
                    } else {
                        //断开连接
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1006);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * MQTT连接成功，开始订阅以下Topic
     */
    private void notifyMQTTConnectSuccess() {
        if (checkCancel()) return;
        log("notifyMQTTConnectSuccess. ");
        try {
            System.out.println("SubcribeTimeStampStart=" + System.currentTimeMillis());
            System.out.println("uplink=" + UPLINK);
            mqttClient.subscribe(UPLINK, 1);
            mqttClient.subscribe(VERIFYSUBSCRIBELINK, 1);
            mqttClient.subscribe(EVENT_TOPIC_GATEWAY_MODECHANGED, 1);
            mqttClient.subscribe(EVENT_TOPIC_PLACE_MAINTAINCHANGED, 1);
            mqttClient.subscribe(EVENT_TOPIC_GATEWAY_DEVICEINCLUDED, 1);
            mqttClient.subscribe(EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED, 1);
            mqttClient.subscribe(EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED, 1);
            mqttClient.subscribe(EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED, 1);
            mqttClient.subscribe(EVENT_TOPIC_DEVICE_UPDATED, 1);
            mqttClient.subscribe(EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE, 1);
            mqttClient.subscribe(EVENT_TOPIC_UPGRADE_MD5, 1);
            mqttClient.subscribe(EVENT_TOPIC_UPGRADE_UPGRADING, 1);
            mqttClient.subscribe(EVENT_TOPIC_UPGRADE_REBOOT, 1);
//            log("MQTT subscribe topics OK="+EVENT_TOPIC_GATEWAY_MODECHANGED);
            //可优化sub时间
            System.out.println("SubcribeTimeStampEnd=" + System.currentTimeMillis());
        } catch (Exception e) {
            log("mqtt subscribe fail!");
            // TODO: 应该视作错误,通知UI
        }
    }

    /**
     * 处理Mqtt收到的消息内容
     *
     * @param topic   接收到消息的Topic
     * @param message 接收到的message消息
     */
    private void handlerMqttMessage(String topic, MqttMessage message) {
        String msg = null;
        if (CONTYPE == WLAN) {
            //非局域网，需要解压缩数据
            msg = ZipUtil.decompressToString(message.getPayload());
        } else {
            msg = message.toString();
        }
        if (AppUtil.isEmulator())
            System.out.println("raw mqtt message=" + msg.toString());
        //事件
        if (topic.contains("event/")) {
            if (null != mEventsCallback) {
                int eventType = SystemConstant.getEventType(topic);
                if (-1 != eventType)
                    mEventsCallback.onEventsCallback(uid, eventType, msg.toString());
            }
        } else if (topic.contains(mMQTTClientID)) {
            //Data数据
            handleGetData(msg);
        } else {
            log("discard this message");
        }
    }

    //设置Topic参数
    private void setTopics() {
        if (topics == null) {
            topics = new String[]{
                    VERIFYSUBSCRIBELINK, //
                    DOWNLINK, //
                    UPLINK, //
                    EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED, //
                    EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED, //
                    EVENT_TOPIC_GATEWAY_MODECHANGED, //
                    EVENT_TOPIC_PLACE_MAINTAINCHANGED, //
                    EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED, //
                    EVENT_TOPIC_GATEWAY_DEVICEINCLUDED, //
                    EVENT_TOPIC_DEVICE_UPDATED, //
                    EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE, //
                    EVENT_TOPIC_UPGRADE_MD5, //
                    EVENT_TOPIC_UPGRADE_UPGRADING, //
                    EVENT_TOPIC_UPGRADE_REBOOT
            };
        }
    }

    /**
     * 根据连接类型格式化Topic
     *
     * @param TYPE LAN 1  WLAN 2
     * @param uid
     */
    private void formatTopic(int TYPE, String uid) {
        if (TYPE == WLAN) {
            if (TextUtils.isEmpty(uid)) {
                return;
            }
            String optionTopic = MD5Util.string2MD5(uid);
            String digestTopic = MD5Util.string2MD5("a" + uid + "b" + password + "c");
            VERIFYPUBLISHLINK = String.format(DOWNLINK, optionTopic);
            VERIFYSUBSCRIBELINK = String.format(UPLINK, optionTopic, mMQTTClientID);
            DOWNLINK = String.format(DOWNLINK, digestTopic);
            UPLINK = String.format(UPLINK, digestTopic, mMQTTClientID);
            EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED = String.format(EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED, digestTopic);
            EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED = String.format(EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED, digestTopic);
            EVENT_TOPIC_GATEWAY_MODECHANGED = String.format(EVENT_TOPIC_GATEWAY_MODECHANGED, digestTopic);
            EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED = String.format(EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED, digestTopic);
            EVENT_TOPIC_GATEWAY_DEVICEINCLUDED = String.format(EVENT_TOPIC_GATEWAY_DEVICEINCLUDED, digestTopic);
            EVENT_TOPIC_DEVICE_UPDATED = String.format(EVENT_TOPIC_DEVICE_UPDATED, digestTopic);
            EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE = String.format(EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE, digestTopic);
            EVENT_TOPIC_UPGRADE_MD5 = String.format(EVENT_TOPIC_UPGRADE_MD5, digestTopic);
            EVENT_TOPIC_UPGRADE_UPGRADING = String.format(EVENT_TOPIC_UPGRADE_UPGRADING, digestTopic);
            EVENT_TOPIC_UPGRADE_REBOOT = String.format(EVENT_TOPIC_UPGRADE_REBOOT, digestTopic);
        } else {
            DOWNLINK = "device_core";
            UPLINK = mMQTTClientID;
            EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED = SystemConstant.EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED;
            EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED = SystemConstant.EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED;
            EVENT_TOPIC_GATEWAY_MODECHANGED = SystemConstant.EVENT_TOPIC_GATEWAY_MODECHANGED;
            EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED = SystemConstant.EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED;
            EVENT_TOPIC_GATEWAY_DEVICEINCLUDED = SystemConstant.EVENT_TOPIC_GATEWAY_DEVICEINCLUDED;
            EVENT_TOPIC_DEVICE_UPDATED = SystemConstant.EVENT_TOPIC_DEVICE_UPDATED;
            EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE = SystemConstant.EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE;
            EVENT_TOPIC_UPGRADE_MD5 = SystemConstant.EVENT_TOPIC_UPGRADE_MD5;
            EVENT_TOPIC_UPGRADE_UPGRADING = SystemConstant.EVENT_TOPIC_UPGRADE_UPGRADING;
            EVENT_TOPIC_UPGRADE_REBOOT = SystemConstant.EVENT_TOPIC_UPGRADE_REBOOT;
        }
        setTopics();
    }

    // App 所有信息发送给 device_core
    // 发送 MQTT 消息给 TOPIC_DEVICE_CORE

    /**
     * 初始化MQTT参数
     */
    public void initMQTT() {
        if (checkCancel()) return;
        Log.v("Tag", "initMQTT. mqttHost = " + connectHost);
        try {
            if (null == mMQTTClientID) {
                mMQTTClientID = AQApplication.getInstance().getMqttClientId();
            }

            String t = "" + (System.currentTimeMillis() % 999);
            String id  = mMQTTClientID + t;
            System.out.println("client id =" + id);

            mqttClient = new MqttClient(connectHost, id, new MemoryPersistence());
            mMqttOptions = new MqttConnectOptions();
            mMqttOptions.setCleanSession(false);
            mMqttOptions.setUserName(mqttUserName);
            mMqttOptions.setPassword(mqttPassWord.toCharArray());
            mMqttOptions.setConnectionTimeout(10);
            mMqttOptions.setKeepAliveInterval(20);
            mMqttOptions.setAutomaticReconnect(true);
            mqttClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("mqtt connection lost reason:" + cause.toString());

                    Intent intent = new Intent();
                    intent.setAction("connect_event_offline");
                    context.sendBroadcast(intent);
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                }

                @Override
                public void messageArrived(String topicName, MqttMessage message) throws Exception {
                    //处理消息
                    handlerMqttMessage(topicName, message);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 检查是否已取消链接
     *
     * @return
     */
    private boolean checkCancel() {
        if (isExist)
            return true;
        return false;
    }

    public void connect() {
        if (checkCancel()) return;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //初始化MQTT
                    initMQTT();
                    //连接MQTT参数
                    mqttClient.connect(mMqttOptions);
                    //不报异常则连接成功
                    notifyMQTTConnectSuccess();
                    SystemConstant.isRunning = true;
                    if (CONTYPE == WLAN) {
                        //TOPICK验证
                        encryTopicCheck();
                    } else if (CONTYPE == LAN) {
                        //局域网连接
                        sendConnect();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    //局域网连接
                    sendConnect();
                }
            }
        }).start();
    }

    /**
     * Topic验证
     */
    private void encryTopicCheck() {
        JSONObject jsonParams = new JSONObject();
        try {
            jsonParams.put("u", "admin");
            //将手机号密码进行字符串拼接，然后MD5加密
            jsonParams.put("t", MD5Util.string2MD5("a" + uid + "b" + password + "c"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        LoginManager.getInstance().EncryTopicCheck(this, jsonParams.toString(), VERIFYPUBLISHLINK, new LoginManager.EncryTopicCheckCallBack() {
            @Override
            public void onResponseCallBack(int ret, String str) {
                if (ret == 0) {
                    if (str.equals("0")) {
                        //手机号密码错误
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1005);
                    } else if (str.equals("1")) {
                        //连接成功
                        ConnectionManager.getInstance().onConnectCallback.onConnectStatus(uid, 123, 1004);
                        ping();
                    }
                }
            }
        });
    }

    public void setEventsCallback(EventsCallback callback) {
        mEventsCallback = callback;
    }

    /**
     * 处理收到的数据
     *
     * @param msg
     */
    private void handleGetData(String msg) {

        try {
            JSONObject obj = new JSONObject(msg);
            String type = obj.getString("type");
            long callid = obj.getLong("callid");
            countdowns.remove(String.valueOf(callid));
            // 如果数据是 gateway 返回的 ack, 忽略掉
            if ("ack".equals(type)) {
                System.out.println("ACk 忽略");
                return;
            }
            // 到 mReqRspHashMap 中查找 callid 对应的 ResponseHandler
            ResponseHandler rspHandler = mReqRspHashMap.get(callid);
            if (null != rspHandler) {
                // 找到了! 呼叫其中的回调处理函数
                rspHandler.getCallback().onResponseCallback(this, msg);
                // 从 HashMap 中删除此映射
                mReqRspHashMap.remove(callid);
                if (flags.size() == 0 && isChecked) {
                    iConnectionEntity.onBoxMessageAllOver(0);
                    isChecked = false;
                }
            } else {
                logw("Can NOT find ResponseHandler in HashMap");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     *
     * @param uid
     * @param message
     * @param topic
     */
    public void sendMessage(String uid, String message, String topic) {
        if (checkCancel()) return;
        log("sendMessage.uid = " + uid + ", message = " + message);
        try {
            // 需要添加 2 个参数: clientid, source
            JSONObject jMessage = new JSONObject(message);
            // jMessage.put("clientid", "device_core");
            jMessage.put("source", mMQTTClientID);
            byte[] bytes = null;
            if (CONTYPE == WLAN) {
                //非局域网需要压缩数据
                bytes = ZipUtil.compress(jMessage.toString().getBytes());
            } else {
                bytes = jMessage.toString().getBytes();
            }
            MqttMessage msg = new MqttMessage(bytes);
            mqttClient.publish(topic, msg);
        } catch (MqttException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     *
     * @param uid
     * @param message
     */
    public void sendMessage(String uid, String message) {
        if (checkCancel()) return;
        log("sendMessage. uid = " + uid + ", message = " + message);
        try {
            // 需要添加 2 个参数: clientid, source
            JSONObject jMessage = new JSONObject(message);
            // jMessage.put("clientid", "device_core");
            jMessage.put("source", mMQTTClientID);
            byte[] bytes = null;
            if (CONTYPE == WLAN) {
                bytes = ZipUtil.compress(jMessage.toString().getBytes());
            } else {
                bytes = jMessage.toString().getBytes();
            }
            MqttMessage msg = new MqttMessage(bytes);
            mqttClient.publish(DOWNLINK, msg);
        } catch (MqttException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送Notify
     *
     * @param message
     * @param topic
     */
    public void sendNotify(String message, String topic) {
        log("sendNotify.Message= " + message + ", topic = " + topic);
        try {
            MqttMessage msg = new MqttMessage(message.getBytes());
            mqttClient.publish(topic, msg);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 断开连接
     */
    public void disConnect() {
        unRegister();
        isExist = true;
        if (mqttClient != null) {
            try {
                mqttClient.unsubscribe(topics);
                log("MQTT unsubscribe topics OK");
                mqttClient.close();
            } catch (Exception e) {
                log("mqtt unsubscribe fail!");
                e.printStackTrace();
            }
        }
        if (mqttScheduler != null)
            mqttScheduler.shutdown();
        ConnectionManager.getInstance().disConnectByUid(uid);
        destory();
    }

    /**
     * 重置连接，将参数初始化
     */
    public void resetConnect() {
        CONTYPE = 0;
        DOWNLINK = "DOWNLINK/%s/device_core";
        UPLINK = "UPLINK/%1$s/%2$s";
        EVENT_TOPIC_CHANNEL_SENSORVALUEUPDATED = "UPLINK/%s/event/channel.sensorvalueUpdated";
        EVENT_TOPIC_CHANNEL_BASICVALUEUPDATED = "UPLINK/%s/event/channel.basicvalueUpdated";
        EVENT_TOPIC_GATEWAY_MODECHANGED = "UPLINK/%s/event/gateway.modeChanged";
        EVENT_TOPIC_GATEWAY_DEVICEEXCLUDED = "UPLINK/%s/event/gateway.deviceExcluded";
        EVENT_TOPIC_GATEWAY_DEVICEINCLUDED = "UPLINK/%s/event/gateway.deviceIncluded";
        EVENT_TOPIC_DEVICE_UPDATED = "UPLINK/%s/event/DeviceManager.deviceUpdated";
        EVENT_TOPIC_UPGRADE_DOWNLOAD_PERCENTAGE = "UPLINK/%s/event/SystemManager.FirmwareDownloadPercentage";
        EVENT_TOPIC_UPGRADE_MD5 = "UPLINK/%s/event/SystemManager.FirmwareMD5";
        EVENT_TOPIC_UPGRADE_UPGRADING = "UPLINK/%s/event/SystemManager.FirmwareUpgrading";
        EVENT_TOPIC_UPGRADE_REBOOT = "UPLINK/%s/event/SystemManager.Reboot";
        try {
            mqttClient.unsubscribe(topics);
            log("MQTT unsubscribe topics OK");
            mqttClient.close();
        } catch (Exception e) {
            log("mqtt unsubscribe fail!");
            e.printStackTrace();
        }
        if (mqttScheduler != null)
            mqttScheduler.shutdown();
//        ConnectionManager.getInstance().disConnectByUid(uid);
//        destory();
        mqttClient = null;
    }

    /**
     * 判断是否连接
     *
     * @return
     */
    public boolean isConnect() {
        if (isExist) {
            return false;
        }
        if (!mqttClient.isConnected()) {
            return false;
        }
        return true;
    }

    /**
     * 断开连接
     */
    public void destory() {
        mqttClient = null;
        mMQTTClientID = null;
        uid = null;
        password = null;
        userName = null;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setMqttClient() {
        this.mqttClient = mqttClient;
    }

    public MqttClient getMqttClient() {
        return ConnectionManager.getInstance().getMqttClient();
    }

    private void log(String msg) {
        Log.v(Tag, msg);
    }

    private void logw(String msg) {
        Log.w(Tag, msg);
    }

    /**
     * 旧的ping函数
     */
    private void ping() {
        log("startPing()");
        mqttScheduler = Executors.newSingleThreadScheduledExecutor();
        mqttScheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    JSONObject jsParams = new JSONObject();
                    jsParams.put("clientid", mMQTTClientID);
                    System.out.println("To Send Ping");
                    LoginManager.getInstance().Ping(ConnectionEntity.this, jsParams.toString(), new LoginManager.PingCallBack() {
                        @Override
                        public void onPingResponseCallBack(int ret, String str) {
                            System.out.println("Got Pong");

                            Intent intent = new Intent();
                            intent.setAction("connect_event_online");
                            context.sendBroadcast(intent);
                        }
                    });
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, 0 * 1000, 150 * 1000, TimeUnit.MILLISECONDS);
    }

    /**
     * 局域网搜索
     *
     * @param context
     * @param did
     */
    private void lanSearch(Context context, final String did) {
        LanSearchUtil.getInstance().search(context, did, new LanSearchUtil.SearchResultInterface() {
            @Override
            public void onResultCallBack(int ret, Object object) {
                //3g 4g上网重置连接
                if (CONTYPE == 0) {
                    CONTYPE = WLAN;
                    init(CONTYPE, WlanHost);
                }
            }

            @Override
            public void onResultIPCallBack(String uid, String ip) {
                System.out.println("uid=" + uid + "ip=" + ip);
                System.out.println("did=" + did + "uid+" + uid);
                //局域网搜索到后
                if (did.equals(uid)) {
                    CONTYPE = LAN;
                    init(CONTYPE, ip);
                }
            }
        });
    }

    public interface EventsCallback {
        public void onEventsCallback(String UID, int eventType, String data);
    }
}